﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;
using System.Linq;

namespace TasksLibrary.Extensions
{
    public static class Extension
    {
        private static DispatcherQueue taskQueue = new DispatcherQueue();

        public static Choice ChoiceWithTimeout<T0, T1>(
            this PortSet<T0, T1> portSet,
            Handler<T0> t0Handler,
            Handler<T1> t1Handler,
            Handler<DateTime> timeoutHandler,
            TimeSpan timeout)
        {
            var timeoutPort = new Port<DateTime>();
            taskQueue.EnqueueTimer(timeout, timeoutPort);
            return Arbiter.Choice(
                portSet.Receive(t0Handler),
                portSet.Receive(t1Handler),
                timeoutPort.Receive(timeoutHandler)
            );
        }

        public static void AnswerForMessage<TBody>(this Update<TBody, PortSet<DefaultUpdateResponseType, Fault>> Message, object BaseMessage) where TBody : new()
        {
            try
            {
                if (Message == null || BaseMessage == null) return;

                bool canWork = false;
                Type messageType = Message.GetType();
                Type basemessageType = BaseMessage.GetType();
                Type objType = typeof(object);
                for (int i = 0; i < 5; i++)
                {
                    if (messageType.IsGenericType && basemessageType.IsGenericType)
                    {
                        if (messageType.GetGenericTypeDefinition() == typeof(Update<,>) && basemessageType.GetGenericTypeDefinition() == typeof(Update<,>))
                        {
                            canWork = true;
                            break;
                        }
                    }
                    if (messageType.BaseType == objType || basemessageType.BaseType == objType) break;
                    messageType = messageType.BaseType;
                    basemessageType = basemessageType.BaseType;
                }

                if (canWork)
                {
                    var PropertiesMessage = Message.GetType().GetProperties();
                    TaskMessageRequest MessageBody = null;
                    foreach (var property in PropertiesMessage)
                        if (property.Name == "Body" && Inc.Types.CheckBaseType(property.PropertyType, typeof(TaskMessageRequest)))
                        {
                            MessageBody = (TaskMessageRequest)property.GetValue(Message, null);
                            break;
                        }

                    var PropertiesBaseMessage = BaseMessage.GetType().GetProperties();
                    TaskMessageRequest BaseMessageBody = null;
                    foreach (var property in PropertiesBaseMessage)
                        if (property.Name == "Body" && Inc.Types.CheckBaseType(property.PropertyType, typeof(TaskMessageRequest)))
                        {
                            BaseMessageBody = (TaskMessageRequest)property.GetValue(BaseMessage, null);
                            break;
                        }

                    if (MessageBody != null && BaseMessageBody != null)
                    {
                        MessageBody.TaskId = BaseMessageBody.TaskId;
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        public static void FromTask<TBody>(this Update<TBody, PortSet<DefaultUpdateResponseType, Fault>> Message, Tasks.Task TaskFrom) where TBody : new()
        {
            try
            {
                if (Message == null) return;

                bool canWork = false;
                Type messageType = Message.GetType();
                Type objType = typeof(object);
                for (int i = 0; i < 5; i++)
                {
                    if (messageType.IsGenericType)
                    {
                        if (messageType.GetGenericTypeDefinition() == typeof(Update<,>))
                        {
                            canWork = true;
                            break;
                        }
                    }
                    if (messageType.BaseType == objType) break;
                    messageType = messageType.BaseType;
                }

                if (canWork)
                {
                    var PropertiesMessage = Message.GetType().GetProperties();
                    TaskMessageRequest MessageBody = null;
                    foreach (var property in PropertiesMessage)
                        if (property.Name == "Body" && Inc.Types.CheckBaseType(property.PropertyType, typeof(TaskMessageRequest)))
                        {
                            MessageBody = (TaskMessageRequest)property.GetValue(Message, null);
                            break;
                        }

                    if (MessageBody != null)
                    {
                        MessageBody.TaskId = TaskFrom.Id;
                    }
                }
            }
            catch (Exception)
            {
            }
        }
    }
}